#include "stdafx.h"
#include "nextStep.h"
#include <string>
#include <iostream>
#include <fstream>
#include <QTime>
#include <QDate>

//RAM
unordered_map<int,unsigned int> hRAM;
//ROM
unordered_map<int,unsigned int> hROM;


void updateTime(){
  QTime curTime=QTime::currentTime();
  QDate curDate=QDate::currentDate();
  hRAM[0]=curTime.second();
  hRAM[1]=curTime.minute();
  hRAM[2]=curTime.hour();
  hRAM[3]=curDate.day();
  hRAM[4]=curDate.month();
  hRAM[5]=curDate.year();
}

void loadProg(string fileName){
  ifstream file;
  file.open(fileName.c_str());
  int nVal,val;
  file >> nVal;
  int cur=0;
  for(int v=0;v<nVal;v++){
    file>>val;
    cur=2*cur+val;
    if((v+1)%32==0){
      hROM[v/32]=cur;
      cur=0;
    }
  }
  file.close();
}


int getPrev(vector<Variable>& vars, vector<int> args){
  int i=0;
  while(1){
    if(vars[args[i]].fun==LRAM || vars[args[i]].fun==LROM)
      return args[i];
    i++;
  }
}

int getVal(vector<Variable>& vars, vector<int> args){
  int i=0;
  while(1){
    if(vars[args[i]].fun!=LRAM && vars[args[i]].fun!=LROM)
      return args[i];
    i++;
  }
}

void NextStep(vector<Variable>& vars,vector<bool>& entrees,unordered_map<string,int> &namesIn,vector<int>& ramAddr,vector<int>& romAddr,vector<int>& orderedRamRomValues)
{
  int nVars=vars.size();
  // On met a jour les registres
  for(int i = 0; i<nVars; i++)
    if(vars[i].fun == LREGO)
      vars[i].valeur = vars[vars[i].args[0]].valeur;
  int numEntree;
  // On met a jour les variables
  for(int i=0; i<nVars; i++)
    {


      switch(vars[i].fun)
	{
	case IN:
	  numEntree=namesIn[string(vars[i].name)];
	  vars[i].valeur = entrees[numEntree];
	  break;
	case LNOT:
	  vars[i].valeur = !vars[vars[i].args[0]].valeur;
	  break;
	case LOR:
	  vars[i].valeur = vars[vars[i].args[0]].valeur || vars[vars[i].args[1]].valeur;
	  break;
	case LAND:
	  vars[i].valeur = vars[vars[i].args[0]].valeur && vars[vars[i].args[1]].valeur;
	  break;
	case LXOR:
	  vars[i].valeur = Xor(vars[vars[i].args[0]].valeur, vars[vars[i].args[1]].valeur);
	  break;
	case LREGI:
	  vars[i].valeur = vars[vars[i].args[0]].valeur;
	  break;
	case LRAM:
	case LROM:
	  //Si c'est la case de tête, il faut lire le enable sinon, il faut lire la valeur
	  if(vars[i].args.size()==1){
	    vars[i].doWrite=vars[vars[i].args[0]].valeur;
	    vars[i].multA=1;
	    //selon le cas, l'un des valeurs n'as aucun sens, ce n'est pas grave.
	    vars[i].valeur=vars[vars[i].args[0]].toRam%2;
	    vars[i].toRam=vars[vars[i].args[0]].toRam/2;
	  }
	  else{
	    unsigned int last = 1<<31;
	    unsigned int prevRam=getPrev(vars,vars[i].args);
	    unsigned int in=vars[getVal(vars,vars[i].args)].valeur;
	    unsigned int multA=vars[prevRam].multA;

	    if(multA!=0){
	      vars[i].doWrite=vars[prevRam].doWrite;

	      if(multA!=1){
		vars[i].valeur=in*multA+vars[prevRam].valeur;
	      }
	      else{
		vars[i].valeur=in;
	      }
	      if(multA==last){
		vars[i].multA=0;
		vars[i].multV=1;
		vars[i].toAddr=vars[i].valeur;
	      }
	      else
		vars[i].multA=2*multA;
	    }
	    else{
	      unsigned int multV=vars[prevRam].multV;
	      vars[i].toAddr=vars[prevRam].toAddr;
	      vars[i].doWrite=vars[prevRam].doWrite;
	      vars[i].multA=0;

	      unsigned int lastV=vars[i].valeur;
	      if(multV!=1)
		vars[i].valeur=in*multV+vars[prevRam].valeur;
	      else
		vars[i].valeur=in;
	      if(multV==last){

		vars[i].toRam=vars[i].valeur;
		unsigned int addr=vars[i].toAddr;
		unsigned int val=vars[i].toRam;
		//		cout<<"Modif addresse : "<<addr<<endl;
		if(vars[i].doWrite){
		  if(vars[i].fun == LRAM)
		    hRAM[addr]=val;
		  if(vars[i].fun == LROM)
		    hROM[addr]=val;
		  vars[i].valeur=vars[i].toRam;
		  vars[i].toRam=lastV;
		}
		else{

		  if(vars[i].fun == LRAM && hRAM.find(addr)!=hRAM.end()){
		    val=hRAM[addr];
		  }
		  else if(vars[i].fun==LRAM)
		    val=0;

		  if(vars[i].fun == LROM && hROM.find(addr)!=hROM.end())
		    val=hROM[addr];
		  else if(vars[i].fun==LROM)
		    val=0;
		  vars[i].toRam=val;
		}
	      }
	      else{
		vars[i].multV=2*multV;
	      }
	    }
	  }
	  break;
	case LROMO:
	case LRAMO:
	  //selon le cas, l'un des valeurs n'as aucun sens, ce n'est pas grave.
	  vars[i].valeur=vars[vars[i].args[0]].toRam%2;
	  vars[i].toRam=vars[vars[i].args[0]].toRam/2;
	  break;
	default:	// pour vrai ou faux - sont initialises a la lecture du fichier
	  break;
	}
    }
  for(int i=0;i<ramAddr.size();i++){
    if(hRAM.find(ramAddr[i])!=hRAM.end())
      orderedRamRomValues.push_back(hRAM[ ramAddr[i] ]);
    else
      orderedRamRomValues.push_back(0);
  }

  for(int i=0;i<romAddr.size();i++){
    if(hROM.find(romAddr[i])!=hROM.end())
      orderedRamRomValues.push_back(hROM[ romAddr[i] ]);
    else
      orderedRamRomValues.push_back(0);
  }

}

bool Xor(bool a, bool b)
{
	return (a && !b) || (!a && b);
}
